package com.farm.common.security;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import java.util.HashSet;
import java.util.Map;
import java.util.Set;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)//开启注解支持
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    SecurityAuthenticationEntryPoint securityAuthenticationEntryPoint;
    @Autowired
    private ApplicationContext applicationContext;
    @Autowired
    SecurityAuthenticationFilter securityAuthenticationFilter;
    @Autowired
    SecurityAccessDeniedHandler securityAccessDeniedHandler;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers(getAnonymousUrls()).permitAll()
                .antMatchers(
                        "/css/**",
                        "/js/**",
                        "/images/**",
                        "/webjars/**",
                        "/import/test",
                        "**/favicon.ico",
                        "/index.html",
                        "favicon.ico",
                        "/doc.html",
                        "/swagger-resources/**",
                        "/v2/api-docs/**",
                        "/index").permitAll()
                .anyRequest().authenticated()
                // 基于 token，不需要 session 禁用会话的创建（无状态）;
                // 关闭CSRF攻击防护，开启CORS功能（跨域）
                .and().csrf().disable().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                // 匿名访问的路径
                // 开启CORS功能（跨域）
                .and().cors();
        // 自定义过滤器配置
        http.addFilterBefore(securityAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
        // 异常处理配置
        http.exceptionHandling()
                .authenticationEntryPoint(securityAuthenticationEntryPoint)
                .accessDeniedHandler(securityAccessDeniedHandler);
        // http.logout() // 配置注销设置（如果需要）
                // .logoutSuccessHandler(jwtLogoutSuccessHandler) // 自定义注销成功处理器（如果需要）

    }

    // @Bean
    // public AuthenticationManager authenticationManagerBean() throws Exception {
    //     return super.authenticationManagerBean();
    // }

    /**
     * 获取标有注解 AnonymousAccess 的访问路径
     */
    private String[] getAnonymousUrls(){
        System.out.println("======================= 获取标有注解 AnonymousAccess 的访问路径 =======================");
        //查找匿名注解标记URL
        Map<RequestMappingInfo, HandlerMethod> handlerMethods = applicationContext.getBean(RequestMappingHandlerMapping.class).getHandlerMethods();
        Set<String> anonymousUrls = new HashSet<>();
        // 循环 RequestMapping
        for (Map.Entry<RequestMappingInfo, HandlerMethod> infoEntry : handlerMethods.entrySet()) {
            HandlerMethod handlerMethod = infoEntry.getValue();
            // 获取方法上 AnonymousAccess 类型的注解
            AnonymousAccess anonymousAccess = handlerMethod.getMethodAnnotation(AnonymousAccess.class);
            // 如果方法上标注了 AnonymousAccess 注解，就获取该方法的访问全路径
            if (anonymousAccess != null) {
                if (infoEntry.getKey().getPatternsCondition() != null){
                    anonymousUrls.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());
                }
            }
        }
        String[] array = anonymousUrls.toArray(new String[0]);
        System.out.println("有"+array.length+"个匿名访问注解");
        System.out.println("======================= 获取标有注解 AnonymousAccess 的访问路径 =======================");
        return array;
    }

}